///
/// Created by 35111 on 2025/4/3.\n
/// Made By Weng Xuanbin\n
/// Email: Weng.Xuan.bin@outlook.com
/// Version: 1.0.1
///

#ifndef NEXUSBOOST_ARRAY_H
#define NEXUSBOOST_ARRAY_H

#include <Config/Error.h>

namespace wmaker
{
    using LL = long long;

    template<typename DataType,LL TotalSize>
    class Array
    {
        static_assert(TotalSize > 0, "Error00001 Invalid expression.");
    public:

        Array() : index(TotalSize)
        {
            data = new DataType[TotalSize + 1];
        }

        template <typename... Args>
        explicit Array(Args... args)
        {
            static_assert(sizeof...(args) <= TotalSize, "Error00002 Initial elements exceed capacity.");
            data = new DataType[TotalSize+1];
            ((data[index++] = static_cast<DataType>(args)), ...);
        }

        DataType& operator[](LL _index)
        {
            WMaker_Error(_index > TotalSize - 1, "Error00007", "Array index out of range.");
            WMaker_Error(_index < 0, "Error00007", "Array index out of range.");
            WMaker_Error(_index >= index, "Error00003", "This position has no data written. index: " + std::to_string(_index));
            return data[_index];
        }

        const DataType& operator[](LL _index) const
        {
            WMaker_Error(_index > TotalSize - 1, "Error00007", "Array index out of range.");
            WMaker_Error(_index < 0, "Error00007", "Array index out of range.");
            WMaker_Error(_index >= index, "Error00003", "This position has no data written.");
            return data[_index];
        }


//        Array& operator=(const Array&) = delete;

        template<LL Size>
        void operator+(const Array<DataType, Size>& arr) {
            WMaker_Error(index + arr.size() > TotalSize, "Error00006", "Array will be full.");
            for (LL i = 0; i < arr.size(); i++)
                data[index++] = arr[i];
        }

        [[nodiscard]] LL size() const
        {
            return index;
        }

        [[nodiscard]] LL totalsize() const
        {
            return TotalSize;
        }

        [[nodiscard]] bool empty() const
        {
            return index == 0;
        }

        void clear()
        {
            index = 0;
        }

        void totalclear()
        {
            delete[] data;
            data = new DataType[TotalSize+1];
        }

        void pop()
        {
            WMaker_Error(index == 0, "Error00005", "Array is empty.");
            index--;
        }

        void pop(int _index)
        {
            WMaker_Error(index == 0, "Error00005", "Array is empty.");
            WMaker_Error(_index < 0, "Error00007", "Array index out of range.");
            WMaker_Error(_index > index - 1, "Error00007", "Array index out of range.");
            for (LL i = _index; i < index-1; i++)
                data[i] = data[i+1];
            index--;
        }

        void erase(int first_index, int last_index)
        {
            WMaker_Error(index == 0, "Error00005", "Array is empty.");
            WMaker_Error(first_index < 0, "Error00007", "Array index out of range.");
            WMaker_Error(last_index < first_index, "Error00007", "Array index out of range.");
            WMaker_Error(last_index >= index, "Error00007", "Array index out of range.");
            for (LL i = last_index + 1; i < index; i++) {
                data[i - (last_index - first_index) - 1] = data[i];
            }
            index -= last_index - first_index + 1;
        }

        void insert(int _index, DataType value)
        {
            WMaker_Error(index >= TotalSize, "Error00004", "Array is full.");
            WMaker_Error(_index < 0, "Error00007", "Array index out of range.");
            WMaker_Error(_index > index, "Error00007", "Array index out of range.");
            for (LL i = index; i > _index; --i)
                data[i] = data[i-1];

            data[_index] = value;
            index++;
        }

        template<LL Size>
        void insert(int _index, Array<DataType, Size> array)
        {
            WMaker_Error(index + array.size() > TotalSize, "Error00006", "Array will be full.");
            WMaker_Error(_index < 0, "Error00007", "Array index out of range.");
            WMaker_Error(_index > index, "Error00007", "Array index out of range.");

            for (LL i = index - 1; i >= _index; --i)
                data[i + array.size()] = data[i];

            for (LL j = 0; j < array.size(); ++j)
                data[_index + j] = static_cast<DataType>(array[j]);

            index += array.size();
        }

        void pushback(DataType value)
        {
            WMaker_Error(index >= TotalSize, "Error00004", "Array is full.");
            this->data[index++] = value;
        }

        template<LL Size>
        void append(const Array<DataType, Size> array)
        {
            WMaker_Error(index + array.size() > TotalSize, "Error00006", "Array will be full.");
            for (LL i = 0; i < array.size(); ++i)
                data[index++] = array[i];
        }

        void release()
        {
            delete[] data;
            data = nullptr;
        }

    private:
        DataType* data;
        LL index = 0;
    };
}

/// Error00001: Invalid expression\n
/// Error00002: Initial elements exceed capacity\n
/// Error00003: Array this position has no data written\n
/// Error00004: Array is full\n
/// Error00005: Array is empty\n
/// Error00006: Array will be full\n
/// Error00007: Array index out of range\n

#endif //NEXUSBOOST_ARRAY_H